﻿#region header

//  ***************************************************************************
// *                                LICENSE
//  ***************************************************************************
//  * "Haplous" .NET Simple 2D Game Framework
//  * 
//  * Copyright © Jonathan Evans 2014-2014
//  * 
//  * This program is free software; you can redistribute it and/or
//  * modify it under the terms of the GNU General Public License
//  * as published by the Free Software Foundation; either version 2
//  * of the License, or (at your option) any later version.
//  * 
//  * This program is distributed in the hope that it will be useful,
//  * but WITHOUT ANY WARRANTY; without even the implied warranty of
//  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  * GNU General Public License for more details.
//  * 
//  * You should have received a copy of the GNU General Public License
//  * along with this program; if not, write to the Free Software
//  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
//  * 
//  ***************************************************************************
//  * 
//  * Contact: opencollar@googlemail.com
//  * 
//  * Website: http://haplous.codeplex.com/
//  *
//  * NuGet:   http://www.nuget.org/packages/haplous/
//  *
//  * File:    Haplous/Haplous.Tests/PositionInt32Tests.cs
//  *
//  ***************************************************************************

#endregion

using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Haplous.Tests
{
    /// <summary>
    ///     Tests to validate the behavior of the <see cref="PositionInt32" /> class.
    /// </summary>
    [TestClass]
    public class PositionInt32Tests
    {
        /// <summary>
        ///     Test that the <see cref="PositionInt32" /> method behaves as expected.
        /// </summary>
        [TestMethod]
        public void PositionInt32Test()
        {
            var position = new PositionInt32();
            Assert.IsNotNull(position, "Default constructor always creates an instance.");
            Assert.AreEqual(0, position.X, "X property defaults to 0.");
            Assert.AreEqual(0, position.Y, "Y property defaults to 0.");
        }

        /// <summary>
        ///     Test that the <see cref="PositionInt32" /> method behaves as expected.
        /// </summary>
        [TestMethod]
        public void PositionInt32Test1()
        {
            var position = new PositionInt32(1, 1);
            Assert.IsNotNull(position, "Coordinate constructor always creates an instance.");
            Assert.AreEqual(1, position.X, "X property is correctly set to 1.");
            Assert.AreEqual(1, position.Y, "Y property is correctly set to 1.");

            position = new PositionInt32(1, 99);
            Assert.IsNotNull(position, "Coordinate constructor always creates an instance.");
            Assert.AreEqual(1, position.X, "X property is correctly set to 1.");
            Assert.AreEqual(99, position.Y, "Y property is correctly set to 1.");

            position = new PositionInt32(-10, -99);
            Assert.IsNotNull(position, "Coordinate constructor always creates an instance.");
            Assert.AreEqual(-10, position.X, "X property is correctly set to -10.");
            Assert.AreEqual(-99, position.Y, "Y property is correctly set to -99.");
        }

        /// <summary>
        ///     Test that the <see cref="PositionInt32.Add(PositionInt32)" /> method behaves as expected.
        /// </summary>
        [TestMethod]
        public void AddTest()
        {
            var position = new PositionInt32(0, 0);
            Assert.AreEqual(0, position.X, "X property is correctly set to 0 at start.");
            Assert.AreEqual(0, position.Y, "Y property is correctly set to 0 at start.");

            var position1 = new PositionInt32(1, 1);
            position.Add(position1);
            Assert.AreEqual(1, position.X, "X property is correctly set to 1 after adding (1, 1).");
            Assert.AreEqual(1, position.Y, "Y property is correctly set to 1 after adding (1, 1).");

            var position2 = new PositionInt32(5, 10);
            position.Add(position2);
            Assert.AreEqual(6, position.X, "X property is correctly set to 6 after adding (5, 10).");
            Assert.AreEqual(11, position.Y, "Y property is correctly set to 11 after adding (5, 10).");

            var position3 = new PositionInt32(-5, -10);
            position.Add(position3);
            Assert.AreEqual(1, position.X, "X property is correctly set to 1 after adding (-5, -10).");
            Assert.AreEqual(1, position.Y, "Y property is correctly set to 1 after adding (-5, -10).");

            position.Add(position3);
            Assert.AreEqual(-4, position.X, "X property is correctly set to -4 after adding (-5, -10).");
            Assert.AreEqual(-9, position.Y, "Y property is correctly set to -9 after adding (-5, -10).");
        }

        /// <summary>
        ///     Test that the <see cref="PositionInt32.Add(int, int)" /> method behaves as expected.
        /// </summary>
        [TestMethod]
        public void AddTest1()
        {
            var position = new PositionInt32(0, 0);

            Assert.AreEqual(0, position.X, "X property is correctly set to 0 at start.");
            Assert.AreEqual(0, position.Y, "Y property is correctly set to 0 at start.");

            position.Add(1, 1);
            Assert.AreEqual(1, position.X, "X property is correctly set to 1 after adding (1, 1).");
            Assert.AreEqual(1, position.Y, "Y property is correctly set to 1 after adding (1, 1).");

            position.Add(5, 10);
            Assert.AreEqual(6, position.X, "X property is correctly set to 6 after adding (5, 10).");
            Assert.AreEqual(11, position.Y, "Y property is correctly set to 11 after adding (5, 10).");

            position.Add(-5, -10);
            Assert.AreEqual(1, position.X, "X property is correctly set to 1 after adding (-5, -10).");
            Assert.AreEqual(1, position.Y, "Y property is correctly set to 1 after adding (-5, -10).");

            position.Add(-5, -10);
            Assert.AreEqual(-4, position.X, "X property is correctly set to -4 after adding (-5, -10).");
            Assert.AreEqual(-9, position.Y, "Y property is correctly set to -9 after adding (-5, -10).");
        }

        /// <summary>
        ///     Test that the <see cref="PositionInt32.Subtract(PositionInt32)" /> method behaves as expected.
        /// </summary>
        [TestMethod]
        public void SubtractTest()
        {
            var position = new PositionInt32(0, 0);
            Assert.AreEqual(0, position.X, "X property is correctly set to 0 at start.");
            Assert.AreEqual(0, position.Y, "Y property is correctly set to 0 at start.");

            var position1 = new PositionInt32(1, 1);
            position.Subtract(position1);
            Assert.AreEqual(-1, position.X, "X property is correctly set to -1 after subtracting (1, 1).");
            Assert.AreEqual(-1, position.Y, "Y property is correctly set to -1 after subtracting (1, 1).");

            var position2 = new PositionInt32(5, 10);
            position.Subtract(position2);
            Assert.AreEqual(-6, position.X, "X property is correctly set to -6 after subtracting (5, 10).");
            Assert.AreEqual(-11, position.Y, "Y property is correctly set to -11 after subtracting (5, 10).");

            var position3 = new PositionInt32(-5, -10);
            position.Subtract(position3);
            Assert.AreEqual(-1, position.X, "X property is correctly set to -1 after subtracting (-5, -10).");
            Assert.AreEqual(-1, position.Y, "Y property is correctly set to -1 after subtracting (-5, -10).");

            position.Subtract(position3);
            Assert.AreEqual(4, position.X, "X property is correctly set to 4 after subtracting (-5, -10).");
            Assert.AreEqual(9, position.Y, "Y property is correctly set to 9 after subtracting (-5, -10).");
        }

        /// <summary>
        ///     Test that the <see cref="PositionInt32.Subtract(int, int)" /> method behaves as expected.
        /// </summary>
        [TestMethod]
        public void SubtractTest1()
        {
            var position = new PositionInt32(0, 0);
            Assert.AreEqual(0, position.X, "X property is correctly set to 0 at start.");
            Assert.AreEqual(0, position.Y, "Y property is correctly set to 0 at start.");

            position.Subtract(1, 1);
            Assert.AreEqual(-1, position.X, "X property is correctly set to -1 after subtracting (1, 1).");
            Assert.AreEqual(-1, position.Y, "Y property is correctly set to -1 after subtracting (1, 1).");

            position.Subtract(5, 10);
            Assert.AreEqual(-6, position.X, "X property is correctly set to -6 after subtracting (5, 10).");
            Assert.AreEqual(-11, position.Y, "Y property is correctly set to -11 after subtracting (5, 10).");

            position.Subtract(-5, -10);
            Assert.AreEqual(-1, position.X, "X property is correctly set to -1 after subtracting (-5, -10).");
            Assert.AreEqual(-1, position.Y, "Y property is correctly set to -1 after subtracting (-5, -10).");

            position.Subtract(-5, -10);
            Assert.AreEqual(4, position.X, "X property is correctly set to 4 after subtracting (-5, -10).");
            Assert.AreEqual(9, position.Y, "Y property is correctly set to 9 after subtracting (-5, -10).");
        }

        /// <summary>
        ///     Test that the <see cref="PositionInt32.Clone()" /> method behaves as expected.
        /// </summary>
        [TestMethod]
        public void CloneTest()
        {
            var position = new PositionInt32(0, 0);
            Assert.AreEqual(0, position.X, "X property is correctly set to 0 at start.");
            Assert.AreEqual(0, position.Y, "Y property is correctly set to 0 at start.");

            var clone = position.Clone();
            Assert.AreEqual(0, clone.X, "Clone X property is correctly set to 0 at start.");
            Assert.AreEqual(0, clone.Y, "Cloned Y property is correctly set to 0 at start.");

            position = new PositionInt32(10, 66);
            Assert.AreEqual(10, position.X, "X property is correctly set to 10 at start.");
            Assert.AreEqual(66, position.Y, "Y property is correctly set to 66 at start.");

            clone = position.Clone();
            Assert.AreEqual(10, clone.X, "Clone X property is correctly set to 10 at start.");
            Assert.AreEqual(66, clone.Y, "Cloned Y property is correctly set to 66 at start.");
        }

        /// <summary>
        ///     Test that the <see cref="PositionInt32.IsOverlappingTest" /> method behaves as expected.
        /// </summary>
        [TestMethod]
        public void IsOverlappingTest()
        {
            // Starting point
            var firstPosition = new PositionInt32(10, 10);
            var firstSize = new SizeInt32(5, 5);

            var result = firstPosition.IsOverlapping(firstSize, firstPosition, firstSize, firstPosition);
            Assert.IsTrue(result, "First and first item does overlap.");

            // No overlap (above and to left of first).
            var secondPosition = new PositionInt32(0, 0);
            var secondSize = new SizeInt32(5, 5);

            result = firstPosition.IsOverlapping(firstSize, secondPosition, secondSize, firstPosition);
            Assert.IsFalse(result, "First and second items do not overlap.");

            result = secondPosition.IsOverlapping(secondSize, firstPosition, firstSize, secondPosition);
            Assert.IsFalse(result, "Second and first items do not overlap.");

            // No overlap (below and to right of first).
            var thirdPosition = new PositionInt32(20, 20);
            var thirdSize = new SizeInt32(5, 5);

            result = firstPosition.IsOverlapping(firstSize, thirdPosition, thirdSize, firstPosition);
            Assert.IsFalse(result, "First and third items do not overlap.");

            result = thirdPosition.IsOverlapping(thirdSize, firstPosition, firstSize, thirdPosition);
            Assert.IsFalse(result, "Second and first items do not overlap.");

            // Overlap (bottom-right overlaps top-left of first object).
            var fourthPosition = new PositionInt32(8, 8);
            var fourthSize = new SizeInt32(5, 5);

            result = firstPosition.IsOverlapping(firstSize, fourthPosition, fourthSize, firstPosition);
            Assert.IsTrue(result, "First and fourth items do overlap.");

            result = fourthPosition.IsOverlapping(fourthSize, firstPosition, firstSize, fourthPosition);
            Assert.IsTrue(result, "Second and first items do overlap.");

            // Overlap (bottom-right just overlaps top-left of first object).
            var fifthPosition = new PositionInt32(5, 5);
            var fifthSize = new SizeInt32(5, 5);

            result = firstPosition.IsOverlapping(firstSize, fifthPosition, fifthSize, firstPosition);
            Assert.IsTrue(result, "First and fifth items do overlap.");

            result = fifthPosition.IsOverlapping(fifthSize, firstPosition, firstSize, fifthPosition);
            Assert.IsTrue(result, "Second and first items do overlap.");

            // No overlap (just above and to left of first).
            var sixthPosition = new PositionInt32(4, 4);
            var sixthSize = new SizeInt32(5, 5);

            result = firstPosition.IsOverlapping(firstSize, sixthPosition, sixthSize, firstPosition);
            Assert.IsFalse(result, "First and sixth items do not overlap.");

            result = sixthPosition.IsOverlapping(sixthSize, firstPosition, firstSize, sixthPosition);
            Assert.IsFalse(result, "Second and first items do not overlap.");

            // Overlap (top-left just overlaps bottom-right of first object).
            var seventhPosition = new PositionInt32(15, 15);
            var seventhSize = new SizeInt32(5, 5);

            result = firstPosition.IsOverlapping(firstSize, seventhPosition, seventhSize, firstPosition);
            Assert.IsTrue(result, "First and seventh items do overlap.");

            result = seventhPosition.IsOverlapping(seventhSize, firstPosition, firstSize, seventhPosition);
            Assert.IsTrue(result, "Second and first items do overlap.");

            // No overlap (just below and to right of first).
            var eighthPosition = new PositionInt32(16, 16);
            var eighthSize = new SizeInt32(5, 5);

            result = firstPosition.IsOverlapping(firstSize, eighthPosition, eighthSize, firstPosition);
            Assert.IsFalse(result, "First and eighth items do not overlap.");

            result = eighthPosition.IsOverlapping(eighthSize, firstPosition, firstSize, eighthPosition);
            Assert.IsFalse(result, "Second and first items do not overlap.");
        }

        /// <summary>
        ///     Test that the <see cref="Position{T}.Set" /> method behaves as expected.
        /// </summary>
        [TestMethod]
        public void SetTest()
        {
            var position = new PositionInt32(10, 20);

            Assert.AreEqual(10, position.X, "Starting position X property is correctly set to 10 at start.");
            Assert.AreEqual(20, position.Y, "Starting position Y property is correctly set to 20 at start.");

            position.Set(30, 40);

            Assert.AreEqual(30, position.X, "Updated position X property is correctly set to 30 after set.");
            Assert.AreEqual(40, position.Y, "Updated position Y property is correctly set to 40 after set.");
        }

        /// <summary>
        ///     Test that the <see cref="PositionInt32.CorrectHorizontalOverlapTest" /> method behaves as expected.
        /// </summary>
        [TestMethod]
        public void CorrectHorizontalOverlapTest()
        {
            var currentPosition = new PositionInt32(10, 10);
            var currentSize = new SizeInt32(5, 5);

            var newPosition = new PositionInt32(10, 10);
            var newSize = new SizeInt32(5, 5);

            var otherPosition = new PositionInt32(20, 20);
            var otherSize = new SizeInt32(5, 5);

            // No change required.
            var newX = newPosition.CorrectHorizontalOverlap(newSize, otherPosition, otherSize, currentPosition, currentSize);
            Assert.AreEqual(0, newX, "Items that do no overlap should not be corrected.");

            // very close, but no change required.
            newPosition.Set(15, 15);
            newX = newPosition.CorrectHorizontalOverlap(newSize, otherPosition, otherSize, currentPosition, currentSize);
            Assert.AreEqual(0, newX, "Items that do no overlap should not be corrected (close).");

            // Overlap of 1 (approaching from left).
            newPosition.Set(16, 15);
            newX = newPosition.CorrectHorizontalOverlap(newSize, otherPosition, otherSize, currentPosition, currentSize);
            Assert.AreEqual(-1, newX, "Correction of -1 expected.");

            // Overlap of 3 (approaching from left).
            newPosition.Set(18, 15);
            newX = newPosition.CorrectHorizontalOverlap(newSize, otherPosition, otherSize, currentPosition, currentSize);
            Assert.AreEqual(-3, newX, "Correction of -3 expected.");

            currentPosition.X = 30;

            // very close, but no change required (approaching from right).
            newPosition.Set(25, 15);
            newX = newPosition.CorrectHorizontalOverlap(newSize, otherPosition, otherSize, currentPosition, currentSize);
            Assert.AreEqual(0, newX, "Items that do no overlap should not be corrected (close, approaching from right).");

            // Overlap of 1 (approaching from right).
            newPosition.Set(24, 15);
            newX = newPosition.CorrectHorizontalOverlap(newSize, otherPosition, otherSize, currentPosition, currentSize);
            Assert.AreEqual(1, newX, "Correction of 1 expected (approaching from right).");

            // Overlap of 3 (approaching from left).
            newPosition.Set(22, 15);
            newX = newPosition.CorrectHorizontalOverlap(newSize, otherPosition, otherSize, currentPosition, currentSize);
            Assert.AreEqual(3, newX, "Correction of 3 expected (approaching from right).");
        }

        /// <summary>
        ///     Test that the <see cref="PositionInt32.CorrectVerticalOverlapTest" /> method behaves as expected.
        /// </summary>
        [TestMethod]
        public void CorrectVerticalOverlapTest()
        {
            var currentPosition = new PositionInt32(10, 10);
            var currentSize = new SizeInt32(5, 5);

            var newPosition = new PositionInt32(10, 10);
            var newSize = new SizeInt32(5, 5);

            var otherPosition = new PositionInt32(20, 20);
            var otherSize = new SizeInt32(5, 5);

            // No change required.
            var newY = newPosition.CorrectVerticalOverlap(newSize, otherPosition, otherSize, currentPosition, currentSize);
            Assert.AreEqual(0, newY, "Items that do no overlap should not be corrected.");

            // very close, but no change required.
            newPosition.Set(15, 15);
            newY = newPosition.CorrectVerticalOverlap(newSize, otherPosition, otherSize, currentPosition, currentSize);
            Assert.AreEqual(0, newY, "Items that do no overlap should not be corrected (close).");

            // Overlap of 1 (approaching from top).
            newPosition.Set(15, 16);
            newY = newPosition.CorrectVerticalOverlap(newSize, otherPosition, otherSize, currentPosition, currentSize);
            Assert.AreEqual(-1, newY, "Correction of -1 expected.");

            // Overlap of 3 (approaching from top).
            newPosition.Set(15, 18);
            newY = newPosition.CorrectVerticalOverlap(newSize, otherPosition, otherSize, currentPosition, currentSize);
            Assert.AreEqual(-3, newY, "Correction of -3 expected.");

            currentPosition.Y = 30;

            // very close, but no change required (approaching from bottom).
            newPosition.Set(15, 25);
            newY = newPosition.CorrectVerticalOverlap(newSize, otherPosition, otherSize, currentPosition, currentSize);
            Assert.AreEqual(0, newY, "Items that do no overlap should not be corrected (close, approaching from bottom).");

            // Overlap of 1 (approaching from bottom).
            newPosition.Set(15, 24);
            newY = newPosition.CorrectVerticalOverlap(newSize, otherPosition, otherSize, currentPosition, currentSize);
            Assert.AreEqual(1, newY, "Correction of 1 expected (approaching from bottom).");

            // Overlap of 3 (approaching from top).
            newPosition.Set(15, 22);
            newY = newPosition.CorrectVerticalOverlap(newSize, otherPosition, otherSize, currentPosition, currentSize);
            Assert.AreEqual(3, newY, "Correction of 3 expected (approaching from bottom).");
        }

        /// <summary>
        ///     Test that the <see cref="PositionInt32.CorrectOverlapTest" /> method behaves as expected (in simple horizontal or
        ///     vertical movements).
        /// </summary>
        [TestMethod]
        public void CorrectOverlapSimpleTest()
        {
            var currentPosition = new PositionInt32(20, 10);
            var currentSize = new SizeInt32(5, 5);

            var newPosition = new PositionInt32(20, 15);
            var newSize = new SizeInt32(5, 5);

            var otherPosition = new PositionInt32(20, 20);
            var otherSize = new SizeInt32(5, 5);

            // The important test we want to perform here is to ensure that we move the smallest necessary
            // amount to avoid a collision.

            // Y - down

            // No change required (approaching from top but no collision)
            newPosition.CorrectOverlap(newSize, otherPosition, otherSize, currentPosition, currentSize);
            Assert.AreEqual(20, newPosition.X, "Near miss from top: no X correction required.");
            Assert.AreEqual(15, newPosition.Y, "Near miss from top: no Y correction required.");

            // Small change required.
            newPosition.Y = 16;
            newPosition.CorrectOverlap(newSize, otherPosition, otherSize, currentPosition, currentSize);
            Assert.AreEqual(20, newPosition.X, "Near miss from top: no X correction required.");
            Assert.AreEqual(15, newPosition.Y, "Collision from top: Y corrected back to nearest point.");

            // Larger change required.
            newPosition.Y = 19;
            newPosition.CorrectOverlap(newSize, otherPosition, otherSize, currentPosition, currentSize);
            Assert.AreEqual(20, newPosition.X, "Substantial hit from top: no X correction required.");
            Assert.AreEqual(15, newPosition.Y, "Collision from top: Y corrected back to nearest point.");

            // Larger change required. (approaching from top almost jumping)
            newPosition.Y = 24;
            newPosition.CorrectOverlap(newSize, otherPosition, otherSize, currentPosition, currentSize);
            Assert.AreEqual(20, newPosition.X, "Near miss from top: no X correction required.");
            Assert.AreEqual(15, newPosition.Y, "Collision from top: Y corrected back to nearest point.");

            // Change required: jump (approaching from right)
            newPosition.Y = 25;
            newPosition.CorrectOverlap(newSize, otherPosition, otherSize, currentPosition, currentSize);
            Assert.AreEqual(20, newPosition.X, "Near miss from top: no X correction required.");
            Assert.AreEqual(15, newPosition.Y, "Near miss from top (jump): Y correction required.");

            // X - Left

            // No change required (approaching from left but no collision)
            currentPosition.Set(10, 20);
            newPosition.Set(15, 20);
            newPosition.CorrectOverlap(newSize, otherPosition, otherSize, currentPosition, currentSize);
            Assert.AreEqual(15, newPosition.X, "Near miss from left: no X correction required.");
            Assert.AreEqual(20, newPosition.Y, "Near miss from left: no Y correction required.");

            // Small change required (approaching from left)
            newPosition.X = 16;
            newPosition.CorrectOverlap(newSize, otherPosition, otherSize, currentPosition, currentSize);
            Assert.AreEqual(15, newPosition.X, "Near miss from left: X corrected back to nearest point.");
            Assert.AreEqual(20, newPosition.Y, "Near miss from left: no Y correction required.");

            // larger change required (approaching from left)
            newPosition.X = 20;
            newPosition.CorrectOverlap(newSize, otherPosition, otherSize, currentPosition, currentSize);
            Assert.AreEqual(15, newPosition.X, "Near miss from left: X corrected back to nearest point.");
            Assert.AreEqual(20, newPosition.Y, "Near miss from left: no Y correction required.");

            // Change required: jump (approaching from left)
            newPosition.X = 25;
            newPosition.CorrectOverlap(newSize, otherPosition, otherSize, currentPosition, currentSize);
            Assert.AreEqual(15, newPosition.X, "Jump from left: X correction required.");
            Assert.AreEqual(20, newPosition.Y, "Near miss from left: Y correction required.");

            // Y - Up

            // No change required (approaching from bottom but no collision)
            currentPosition.Set(20, 30);
            newPosition.Set(20, 25);
            newPosition.CorrectOverlap(newSize, otherPosition, otherSize, currentPosition, currentSize);
            Assert.AreEqual(20, newPosition.X, "Near miss from bottom: no X correction required.");
            Assert.AreEqual(25, newPosition.Y, "Near miss from bottom: no Y correction required.");

            // Small change required.
            newPosition.Y = 24;
            newPosition.CorrectOverlap(newSize, otherPosition, otherSize, currentPosition, currentSize);
            Assert.AreEqual(20, newPosition.X, "Near miss from bottom: no X correction required.");
            Assert.AreEqual(25, newPosition.Y, "Collision from bottom: Y corrected back to nearest point.");

            // Larger change required.
            newPosition.Y = 22;
            newPosition.CorrectOverlap(newSize, otherPosition, otherSize, currentPosition, currentSize);
            Assert.AreEqual(20, newPosition.X, "Substantial hit from bottom: no X correction required.");
            Assert.AreEqual(25, newPosition.Y, "Collision from bottom: Y corrected back to nearest point.");

            // Larger change required. (approaching from bottom almost jumping)
            newPosition.Y = 18;
            newPosition.CorrectOverlap(newSize, otherPosition, otherSize, currentPosition, currentSize);
            Assert.AreEqual(20, newPosition.X, "Near miss from bottom: no X correction required.");
            Assert.AreEqual(25, newPosition.Y, "Collision from bottom: Y corrected back to nearest point.");

            // Change required: jump (approaching from right)
            newPosition.Y = 15;
            newPosition.CorrectOverlap(newSize, otherPosition, otherSize, currentPosition, currentSize);
            Assert.AreEqual(20, newPosition.X, "Near miss from bottom: no X correction required.");
            Assert.AreEqual(25, newPosition.Y, "Near miss from bottom (jump): Y correction required.");

            // X - Right

            // No change required (approaching from right but no collision)
            currentPosition.Set(30, 20);
            newPosition.Set(25, 20);
            newPosition.CorrectOverlap(newSize, otherPosition, otherSize, currentPosition, currentSize);
            Assert.AreEqual(25, newPosition.X, "Near miss from right: no X correction required.");
            Assert.AreEqual(20, newPosition.Y, "Near miss from right: no Y correction required.");

            // Small change required (approaching from right)
            newPosition.X = 24;
            newPosition.CorrectOverlap(newSize, otherPosition, otherSize, currentPosition, currentSize);
            Assert.AreEqual(25, newPosition.X, "Near miss from right: X corrected back to nearest point.");
            Assert.AreEqual(20, newPosition.Y, "Near miss from right: no Y correction required.");

            // larger change required (approaching from right)
            newPosition.X = 18;
            newPosition.CorrectOverlap(newSize, otherPosition, otherSize, currentPosition, currentSize);
            Assert.AreEqual(25, newPosition.X, "Near miss from right: X corrected back to nearest point.");
            Assert.AreEqual(20, newPosition.Y, "Near miss from right: no Y correction required.");

            // Change required: jump (approaching from right)
            newPosition.X = 15;
            newPosition.CorrectOverlap(newSize, otherPosition, otherSize, currentPosition, currentSize);
            Assert.AreEqual(25, newPosition.X, "Jump from right: X correction required.");
            Assert.AreEqual(20, newPosition.Y, "Near miss from right: no Y correction required.");
        }

        /// <summary>
        ///     Test that the <see cref="PositionInt32.CorrectOverlapTest" /> method behaves as expected (in more complex diagonal
        ///     movements).
        /// </summary>
        [TestMethod]
        public void CorrectOverlapComplexTest()
        {
            var currentPosition = new PositionInt32(10, 10);
            var currentSize = new SizeInt32(5, 5);

            var newPosition = new PositionInt32(15, 15);
            var newSize = new SizeInt32(5, 5);

            var otherPosition = new PositionInt32(20, 20);
            var otherSize = new SizeInt32(5, 5);

            // 45 degrees from top/left

            // No change required (approaching from top/left but no collision)
            newPosition.CorrectOverlap(newSize, otherPosition, otherSize, currentPosition, currentSize);
            Assert.AreEqual(15, newPosition.X, "Near miss from top: no X correction required.");
            Assert.AreEqual(15, newPosition.Y, "Near miss from top: no Y correction required.");

            // Change required on X (approaching from top/left.)
            currentPosition.Set(15, 16);
            newPosition.Set(16, 16);
            newPosition.CorrectOverlap(newSize, otherPosition, otherSize, currentPosition, currentSize);
            Assert.AreEqual(15, newPosition.X, "Collision from top/left: X correction required.");
            Assert.AreEqual(16, newPosition.Y, "Collision from top/left: no Y correction required.");

            // Change required on Y (approaching from top/left.)
            currentPosition.Set(16, 15);
            newPosition.Set(16, 16);
            newPosition.CorrectOverlap(newSize, otherPosition, otherSize, currentPosition, currentSize);
            Assert.AreEqual(16, newPosition.X, "Collision from top/left: X correction required.");
            Assert.AreEqual(15, newPosition.Y, "Collision from top/left: no Y correction required.");

            // Change required on X: smaller Y movement (approaching from top/left.)
            currentPosition.Set(15, 15);
            newPosition.Set(16, 17);
            newPosition.CorrectOverlap(newSize, otherPosition, otherSize, currentPosition, currentSize);
            Assert.AreEqual(15, newPosition.X, "Collision from top/left: no X correction required.");
            Assert.AreEqual(17, newPosition.Y, "Collision from top/left: Y correction required.");

            // Change required on Y: smaller X movement (approaching from top/left.)
            currentPosition.Set(15, 15);
            newPosition.Set(17, 16);
            newPosition.CorrectOverlap(newSize, otherPosition, otherSize, currentPosition, currentSize);
            Assert.AreEqual(17, newPosition.X, "Collision from top/left: no X correction required.");
            Assert.AreEqual(15, newPosition.Y, "Collision from top/left: Y correction required.");

            // 45 degrees from top/right
            currentPosition.Set(30, 10);
            newPosition.Set(25, 15);

            // No change required (approaching from top/right but no collision)
            newPosition.CorrectOverlap(newSize, otherPosition, otherSize, currentPosition, currentSize);
            Assert.AreEqual(25, newPosition.X, "Near miss from top: no X correction required.");
            Assert.AreEqual(15, newPosition.Y, "Near miss from top: no Y correction required.");

            // Change required on X (approaching from top/right.)
            currentPosition.Set(30, 16);
            newPosition.Set(24, 16);
            newPosition.CorrectOverlap(newSize, otherPosition, otherSize, currentPosition, currentSize);
            Assert.AreEqual(25, newPosition.X, "Collision from top/right: X correction required.");
            Assert.AreEqual(16, newPosition.Y, "Collision from top/right: no Y correction required.");

            // Change required on Y (approaching from top/right.)
            currentPosition.Set(24, 15);
            newPosition.Set(24, 16);
            newPosition.CorrectOverlap(newSize, otherPosition, otherSize, currentPosition, currentSize);
            Assert.AreEqual(24, newPosition.X, "Collision from top/right: X correction required.");
            Assert.AreEqual(15, newPosition.Y, "Collision from top/right: no Y correction required.");

            // Change required on X: smaller Y movement (approaching from top/right.)
            currentPosition.Set(25, 15);
            newPosition.Set(24, 17);
            newPosition.CorrectOverlap(newSize, otherPosition, otherSize, currentPosition, currentSize);
            Assert.AreEqual(25, newPosition.X, "Collision from top/right: no X correction required.");
            Assert.AreEqual(17, newPosition.Y, "Collision from top/right: Y correction required.");

            // Change required on Y: smaller X movement (approaching from top/right.)
            currentPosition.Set(25, 15);
            newPosition.Set(23, 16);
            newPosition.CorrectOverlap(newSize, otherPosition, otherSize, currentPosition, currentSize);
            Assert.AreEqual(23, newPosition.X, "Collision from top/right: no X correction required.");
            Assert.AreEqual(15, newPosition.Y, "Collision from top/right: Y correction required.");

            // 45 degrees from bottom/left
            currentPosition.Set(10, 30);
            newPosition.Set(15, 25);

            // No change required (approaching from bottom/left but no collision)
            newPosition.CorrectOverlap(newSize, otherPosition, otherSize, currentPosition, currentSize);
            Assert.AreEqual(15, newPosition.X, "Near miss from bottom: no X correction required.");
            Assert.AreEqual(25, newPosition.Y, "Near miss from bottom: no Y correction required.");

            // Change required on X (approaching from bottom/left.)
            currentPosition.Set(15, 24);
            newPosition.Set(16, 24);
            newPosition.CorrectOverlap(newSize, otherPosition, otherSize, currentPosition, currentSize);
            Assert.AreEqual(15, newPosition.X, "Collision from bottom/left: X correction required.");
            Assert.AreEqual(24, newPosition.Y, "Collision from bottom/left: no Y correction required.");

            // Change required on Y (approaching from bottom/left.)
            currentPosition.Set(16, 25);
            newPosition.Set(16, 24);
            newPosition.CorrectOverlap(newSize, otherPosition, otherSize, currentPosition, currentSize);
            Assert.AreEqual(16, newPosition.X, "Collision from bottom/left: X correction required.");
            Assert.AreEqual(25, newPosition.Y, "Collision from bottom/left: no Y correction required.");

            // Change required on X: smaller Y movement (approaching from bottom/left.)
            currentPosition.Set(15, 25);
            newPosition.Set(16, 23);
            newPosition.CorrectOverlap(newSize, otherPosition, otherSize, currentPosition, currentSize);
            Assert.AreEqual(15, newPosition.X, "Collision from bottom/left: no X correction required.");
            Assert.AreEqual(23, newPosition.Y, "Collision from bottom/left: Y correction required.");

            // Change required on Y: smaller X movement (approaching from bottom/left.)
            currentPosition.Set(15, 25);
            newPosition.Set(17, 24);
            newPosition.CorrectOverlap(newSize, otherPosition, otherSize, currentPosition, currentSize);
            Assert.AreEqual(17, newPosition.X, "Collision from bottom/left: no X correction required.");
            Assert.AreEqual(25, newPosition.Y, "Collision from bottom/left: Y correction required.");

            // 45 degrees from bottom/right
            currentPosition.Set(30, 30);
            newPosition.Set(25, 25);

            // No change required (approaching from bottom/right but no collision)
            newPosition.CorrectOverlap(newSize, otherPosition, otherSize, currentPosition, currentSize);
            Assert.AreEqual(25, newPosition.X, "Near miss from bottom: no X correction required.");
            Assert.AreEqual(25, newPosition.Y, "Near miss from bottom: no Y correction required.");

            // Change required on X (approaching from bottom/right.)
            currentPosition.Set(30, 24);
            newPosition.Set(24, 24);
            newPosition.CorrectOverlap(newSize, otherPosition, otherSize, currentPosition, currentSize);
            Assert.AreEqual(25, newPosition.X, "Collision from bottom/right: X correction required.");
            Assert.AreEqual(24, newPosition.Y, "Collision from bottom/right: no Y correction required.");

            // Change required on Y (approaching from bottom/right.)
            currentPosition.Set(24, 30);
            newPosition.Set(24, 24);
            newPosition.CorrectOverlap(newSize, otherPosition, otherSize, currentPosition, currentSize);
            Assert.AreEqual(24, newPosition.X, "Collision from bottom/right: X correction required.");
            Assert.AreEqual(25, newPosition.Y, "Collision from bottom/right: no Y correction required.");

            // Change required on X: smaller Y movement (approaching from bottom/right.)
            currentPosition.Set(25, 30);
            newPosition.Set(24, 23);
            newPosition.CorrectOverlap(newSize, otherPosition, otherSize, currentPosition, currentSize);
            Assert.AreEqual(25, newPosition.X, "Collision from bottom/right: no X correction required.");
            Assert.AreEqual(23, newPosition.Y, "Collision from bottom/right: Y correction required.");

            // Change required on Y: smaller X movement (approaching from bottom/right.)
            currentPosition.Set(25, 30);
            newPosition.Set(23, 24);
            newPosition.CorrectOverlap(newSize, otherPosition, otherSize, currentPosition, currentSize);
            Assert.AreEqual(23, newPosition.X, "Collision from bottom/right: no X correction required.");
            Assert.AreEqual(25, newPosition.Y, "Collision from bottom/right: Y correction required.");
        }
    }
}